//
//  SHDrawerController.m
//  SHDrawerController
//
//  Created by UUPlant on 2022/4/7.
//

#import "SHDrawerController.h"

CGFloat const SHDrawerDefaultWidth = 280.0f;
CGFloat const SHDrawerDefaultAnimationVelocity = 840.0f;
NSTimeInterval const SHDrawerMinimumAnimationDuration = 0.15f;


CGFloat const MMDrawerPanVelocityXAnimationThreshold = 200.0f;

/** The amount of overshoot that is panned linearly. The remaining percentage nonlinearly asymptotes to the max percentage. */
CGFloat const MMDrawerOvershootLinearRangePercentage = 0.75f;

/** The percent of the possible overshoot width to use as the actual overshoot percentage. */
CGFloat const MMDrawerOvershootPercentage = 0.1f;

typedef void (^SHDrawerGestureCompletionBlock)(SHDrawerController * drawerController, UIGestureRecognizer * gesture);

@interface SHCenterContainerView : UIView

@end

@implementation SHCenterContainerView

@end


typedef UIView SHChildContainerView;
@interface SHDrawerController () <UIGestureRecognizerDelegate>

@property (nonatomic, strong) SHChildContainerView *childContainerView;
@property (nonatomic, strong) SHCenterContainerView *centerContainerView;

@property (nonatomic, assign, getter = isAnimatingDrawer) BOOL animatingDrawer;
@property (nonatomic, strong) UIControl *maskControl;

@property (nonatomic, assign) CGRect startingPanRect;
@property (nonatomic, assign) CGRect endPanRect;

@property (nonatomic, copy) SHDrawerGestureCompletionBlock gestureCompletion;

@end

@implementation SHDrawerController

#pragma mark - Initialize
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        [self commonInit];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder {
    self = [super initWithCoder:coder];
    if (self) {
        [self commonInit];
    }
    return self;
}

- (instancetype)initWithCenterViewController:(UIViewController *)centerVC leftVC:(UIViewController *)leftVC rightVC:(UIViewController *)rightVC
{
    NSParameterAssert(centerVC);
    self = [super init];
    if (self) {
        self.centerViewController = centerVC;
        self.leftDrawerViewController = leftVC;
        self.rightDrawerViewController = rightVC;
    }
    return self;
}

- (instancetype)initWithCenterViewController:(UIViewController *)centerVC leftVC:(UIViewController *)leftVC {
    return [self initWithCenterViewController:centerVC leftVC:leftVC rightVC:nil];
}

- (instancetype)initWithCenterViewController:(UIViewController *)centerVC rightVC:(UIViewController *)rightVC {
    return [self initWithCenterViewController:centerVC leftVC:nil rightVC:rightVC];
}

- (void)commonInit {
    self.maximumLeftDrawerWidth = SHDrawerDefaultWidth;
    self.maximumRightDrawerWidth = SHDrawerDefaultWidth;
    self.bezelPanningCenterViewRange = 20.0f;
    self.animationVelocity = SHDrawerDefaultAnimationVelocity;
    
    [self setOpenDrawerGestureModeMask:MMOpenDrawerGestureModeBezelPanningCenterView];
    [self setCloseDrawerGestureModeMask:MMCloseDrawerGestureModeTapCenterView];
    
    self.shouldStretchDrawer = YES;
}

#pragma mark - Lift circle
- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self.view setBackgroundColor:[UIColor redColor]];
    
    [self setupGestureRecognizers];
}

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [self.centerViewController beginAppearanceTransition:YES animated:animated];
    
    if(self.drawerSideState == SHDrawerSideStateLeft) {
        [self.leftDrawerViewController beginAppearanceTransition:YES animated:animated];
    }
    else if(self.drawerSideState == SHDrawerSideStateRight) {
        [self.rightDrawerViewController beginAppearanceTransition:YES animated:animated];
    }
}

-(void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];
//    [self updateShadowForCenterView];
    [self.centerViewController endAppearanceTransition];
    
    if(self.drawerSideState == SHDrawerSideStateLeft) {
        [self.leftDrawerViewController endAppearanceTransition];
    }
    else if(self.drawerSideState == SHDrawerSideStateRight) {
        [self.rightDrawerViewController endAppearanceTransition];
    }
}

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [self.centerViewController beginAppearanceTransition:NO animated:animated];
    if(self.drawerSideState == SHDrawerSideStateLeft) {
        [self.leftDrawerViewController beginAppearanceTransition:NO animated:animated];
    }
    else if (self.drawerSideState == SHDrawerSideStateRight) {
        [self.rightDrawerViewController beginAppearanceTransition:NO animated:animated];
    }
}

- (void)viewDidDisappear:(BOOL)animated{
    [super viewDidDisappear:animated];
    [self.centerViewController endAppearanceTransition];
    if(self.drawerSideState == SHDrawerSideStateLeft) {
        [self.leftDrawerViewController endAppearanceTransition];
    }
    else if (self.drawerSideState == SHDrawerSideStateRight) {
        [self.rightDrawerViewController endAppearanceTransition];
    }
}

#pragma mark - Helper

- (CGRect)visibleRectForDrawerSideState:(SHDrawerSideState)drawerSideState {
    CGRect visibleDrawerFrame = self.view.bounds;
    CGFloat width = self.maximumLeftDrawerWidth;
    if (drawerSideState == SHDrawerSideStateLeft) {
        visibleDrawerFrame.size.width = width;
    } else {
        width = self.maximumRightDrawerWidth;
        visibleDrawerFrame.origin.x = CGRectGetWidth(visibleDrawerFrame) - width;
    }
    return visibleDrawerFrame;
}

-(void)setupGestureRecognizers{
    UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureCallback:)];
    [pan setDelegate:self];
    [self.view addGestureRecognizer:pan];
    
    UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureCallback:)];
    [tap setDelegate:self];
    [self.view addGestureRecognizer:tap];
}

-(UIViewController*)sideDrawerViewControllerForSide:(SHDrawerSideState)drawerSide{
    UIViewController * sideDrawerViewController = nil;
    if(drawerSide != SHDrawerSideStateNormal){
        sideDrawerViewController = [self childViewControllerForSide:drawerSide];
    }
    return sideDrawerViewController;
}

-(UIViewController*)childViewControllerForSide:(SHDrawerSideState)drawerSide{
    UIViewController * childViewController = nil;
    switch (drawerSide) {
        case SHDrawerSideStateLeft:
            childViewController = self.leftDrawerViewController;
            break;
        case SHDrawerSideStateRight:
            childViewController = self.rightDrawerViewController;
            break;
        case SHDrawerSideStateNormal:
            childViewController = self.centerViewController;
            break;
    }
    return childViewController;
}

-(void)prepareToPresentDrawer:(SHDrawerSideState)drawerSideState animated:(BOOL)animated{
    SHDrawerSideState drawerToHide = SHDrawerSideStateNormal;
    if(drawerSideState == SHDrawerSideStateLeft){
        drawerToHide = SHDrawerSideStateRight;
    }
    else if(drawerSideState == SHDrawerSideStateRight){
        drawerToHide = SHDrawerSideStateLeft;
    }
    
    UIViewController * sideDrawerViewControllerToPresent = [self sideDrawerViewControllerForSide:drawerSideState];
    UIViewController * sideDrawerViewControllerToHide = [self sideDrawerViewControllerForSide:drawerToHide];

    [self.childContainerView sendSubviewToBack:sideDrawerViewControllerToHide.view];
    [sideDrawerViewControllerToHide.view setHidden:YES];
    [sideDrawerViewControllerToPresent.view setHidden:NO];
    [self resetDrawerVisualStateForDrawerSide:drawerSideState];
    [sideDrawerViewControllerToPresent.view setFrame:[self visibleRectForDrawerSideState:drawerSideState]];
    [self updateDrawerVisualStateForDrawerSide:drawerSideState percentVisible:0.0];
    [sideDrawerViewControllerToPresent beginAppearanceTransition:YES animated:animated];
}

#pragma mark Gesture Recogizner Delegate Helpers
-(MMCloseDrawerGestureMode)possibleCloseGestureModesForGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer withTouch:(UITouch*)touch{
    CGPoint point = [touch locationInView:self.childContainerView];
    MMCloseDrawerGestureMode possibleCloseGestureModes = MMCloseDrawerGestureModeNone;
    if([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]){
        if([self isPointContainedWithinNavigationRect:point]){
            possibleCloseGestureModes |= MMCloseDrawerGestureModeTapNavigationBar;
        }
        if([self isPointContainedWithinCenterViewContentRectFromLeftDrawer:point]){
            possibleCloseGestureModes |= MMCloseDrawerGestureModeTapCenterView;
        }
    }
    else if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]){
        if([self isPointContainedWithinNavigationRect:point]){
            possibleCloseGestureModes |= MMCloseDrawerGestureModePanningNavigationBar;
        }
        if([self isPointContainedWithinCenterViewContentRect:point]){
            possibleCloseGestureModes |= MMCloseDrawerGestureModePanningCenterView;
        }
        if([self isPointContainedWithinRightBezelRect:point] &&
           self.drawerSideState == SHDrawerSideStateLeft){
            possibleCloseGestureModes |= MMCloseDrawerGestureModeBezelPanningCenterView;
        }
        if([self isPointContainedWithinLeftBezelRect:point] &&
           self.drawerSideState == SHDrawerSideStateRight){
            possibleCloseGestureModes |= MMCloseDrawerGestureModeBezelPanningCenterView;
        }
        if([self isPointContainedWithinCenterViewContentRect:point] == NO &&
           [self isPointContainedWithinNavigationRect:point] == NO){
            possibleCloseGestureModes |= MMCloseDrawerGestureModePanningDrawerView;
        }
    }
    
    return possibleCloseGestureModes;
}

-(MMOpenDrawerGestureMode)possibleOpenGestureModesForGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer withTouch:(UITouch*)touch{
    CGPoint point = [touch locationInView:self.childContainerView];
    MMOpenDrawerGestureMode possibleOpenGestureModes = MMOpenDrawerGestureModeNone;
    if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]){
        if([self isPointContainedWithinNavigationRect:point]){
            possibleOpenGestureModes |= MMOpenDrawerGestureModePanningNavigationBar;
        }
        if([self isPointContainedWithinCenterViewContentRectFromLeftDrawer:point]){
            possibleOpenGestureModes |= MMOpenDrawerGestureModePanningCenterView;
        }
        if([self isPointContainedWithinLeftBezelRect:point] &&
           self.leftDrawerViewController){
            possibleOpenGestureModes |= MMOpenDrawerGestureModeBezelPanningCenterView;
        }
        if([self isPointContainedWithinRightBezelRect:point] &&
           self.rightDrawerViewController){
            possibleOpenGestureModes |= MMOpenDrawerGestureModeBezelPanningCenterView;
        }
    }
    
    return possibleOpenGestureModes;
}

-(BOOL)isPointContainedWithinNavigationRect:(CGPoint)point{
    CGRect navigationBarRect = CGRectNull;
    if([self.centerViewController isKindOfClass:[UINavigationController class]]){
        UINavigationBar * navBar = [(UINavigationController*)self.centerViewController navigationBar];
        navigationBarRect = [navBar convertRect:navBar.bounds toView:self.childContainerView];
        navigationBarRect = CGRectIntersection(navigationBarRect,self.childContainerView.bounds);
    }
    return CGRectContainsPoint(navigationBarRect,point);
}

-(BOOL)isPointContainedWithinCenterViewContentRectFromLeftDrawer:(CGPoint)point {
    CGRect centerViewContentRect = self.centerContainerView.frame;
    CGFloat offsetWidth = self.drawerSideState == SHDrawerSideStateLeft ? self.maximumLeftDrawerWidth : -self.maximumRightDrawerWidth;
    centerViewContentRect = CGRectOffset(centerViewContentRect, offsetWidth, 0);
    centerViewContentRect = CGRectIntersection(centerViewContentRect,self.childContainerView.bounds);
    return (CGRectContainsPoint(centerViewContentRect, point) &&
            [self isPointContainedWithinNavigationRect:point] == NO);
}

-(BOOL)isPointContainedWithinCenterViewContentRect:(CGPoint)point{
    CGRect centerViewContentRect = self.centerContainerView.frame;
    centerViewContentRect = CGRectIntersection(centerViewContentRect,self.childContainerView.bounds);
    return (CGRectContainsPoint(centerViewContentRect, point) &&
            [self isPointContainedWithinNavigationRect:point] == NO);
}

-(BOOL)isPointContainedWithinLeftBezelRect:(CGPoint)point{
    CGRect leftBezelRect = CGRectNull;
    CGRect tempRect;
    CGRectDivide(self.childContainerView.bounds, &leftBezelRect, &tempRect, self.bezelPanningCenterViewRange, CGRectMinXEdge);
    return (CGRectContainsPoint(leftBezelRect, point) &&
            [self isPointContainedWithinCenterViewContentRect:point]);
}

-(BOOL)isPointContainedWithinRightBezelRect:(CGPoint)point{
    CGRect rightBezelRect = CGRectNull;
    CGRect tempRect;
    CGRectDivide(self.childContainerView.bounds, &rightBezelRect, &tempRect, self.bezelPanningCenterViewRange, CGRectMaxXEdge);
    
    return (CGRectContainsPoint(rightBezelRect, point) &&
            [self isPointContainedWithinCenterViewContentRect:point]);
}

#pragma mark - Gesture handlers
- (void)maskControlClick:(UIControl *)sender {
    [self closeDrawerAnimated:YES completion:nil];
}

// TODO: Dush
-(void)tapGestureCallback:(UITapGestureRecognizer *)tapGesture{
    if(self.drawerSideState != SHDrawerSideStateNormal &&
       self.isAnimatingDrawer == NO){
        [self closeDrawerAnimated:YES completion:^(BOOL finished) {
            
        }];
    }
}

-(void)panGestureCallback:(UIPanGestureRecognizer *)panGesture{
    switch (panGesture.state) {
        case UIGestureRecognizerStateBegan:{
            if(self.isAnimatingDrawer){
                [panGesture setEnabled:NO];
                break;
            }
            else {
                self.startingPanRect = self.centerContainerView.frame;
                if (self.drawerSideState == SHDrawerSideStateLeft) {
                    self.startingPanRect = CGRectOffset(self.centerContainerView.frame, self.maximumLeftDrawerWidth, 0);
                } else if (self.drawerSideState == SHDrawerSideStateRight) {
                    self.startingPanRect = CGRectOffset(self.centerContainerView.frame, -self.maximumLeftDrawerWidth, 0);
                }
            }
        }
        case UIGestureRecognizerStateChanged:{
            self.view.userInteractionEnabled = NO;
            CGRect newFrame = self.startingPanRect;
            CGPoint translatedPoint = [panGesture translationInView:self.centerContainerView];
            
            newFrame.origin.x = [self roundedOriginXForDrawerConstriants:CGRectGetMinX(self.startingPanRect)+translatedPoint.x];
            newFrame = CGRectIntegral(newFrame);
            CGFloat xOffset = newFrame.origin.x;

            SHDrawerSideState visibleSide = SHDrawerSideStateNormal;
            CGFloat percentVisible = 0.0;
            if(xOffset > 0 || (self.drawerSideState == SHDrawerSideStateLeft && xOffset<= 0)){
                visibleSide = SHDrawerSideStateLeft;
                percentVisible = MAX(0, xOffset/self.maximumLeftDrawerWidth);
            }
            else if(xOffset < 0 || (self.drawerSideState == SHDrawerSideStateRight && xOffset>= 0)){
                visibleSide = SHDrawerSideStateRight;
                percentVisible = ABS(xOffset)/self.maximumRightDrawerWidth;
            }
            UIViewController * visibleSideDrawerViewController = [self sideDrawerViewControllerForSide:visibleSide];

            if(self.drawerSideState != visibleSide){
                //Handle disappearing the visible drawer
                UIViewController * sideDrawerViewController = [self sideDrawerViewControllerForSide:self.drawerSideState];
                [sideDrawerViewController beginAppearanceTransition:NO animated:NO];
                [sideDrawerViewController endAppearanceTransition];

                //Drawer is about to become visible
                [self prepareToPresentDrawer:visibleSide animated:NO];
                [visibleSideDrawerViewController endAppearanceTransition];
                [self setDrawerSideState:visibleSide];
            }
            else if(visibleSide == SHDrawerSideStateNormal){
                [self setDrawerSideState:SHDrawerSideStateNormal];
            }
            
            [self updateDrawerVisualStateForDrawerSide:visibleSide percentVisible:percentVisible];

            break;
        }
        case UIGestureRecognizerStateEnded:
        case UIGestureRecognizerStateCancelled: {
            self.startingPanRect = CGRectNull;
            CGPoint velocity = [panGesture velocityInView:self.childContainerView];
            [self finishAnimationForPanGestureWithXVelocity:velocity.x completion:^(BOOL finished) {
                if(self.gestureCompletion){
                    self.gestureCompletion(self, panGesture);
                }
            }];
            [panGesture setEnabled:YES];
            self.view.userInteractionEnabled = YES;
            break;
        }
        default:
            break;
    }
}

#pragma mark - Animation helper
-(void)updateDrawerVisualStateForDrawerSide:(SHDrawerSideState)drawerSide percentVisible:(CGFloat)percentVisible {
    
    CATransform3D transform = CATransform3DIdentity;
    UIViewController * sideDrawerViewController;
//        NSLog(@"Dush: %@ %@", @(drawerSide), @(percentVisible));
    if(drawerSide == SHDrawerSideStateLeft) {
        sideDrawerViewController = self.leftDrawerViewController;
        CGFloat distance = MAX(self.maximumLeftDrawerWidth, self.visibleLeftDrawerWidth);
        if (percentVisible <= 1.f) {
            CGFloat tx = (-distance)/1 + (distance*percentVisible/1);
            transform = CATransform3DMakeTranslation(tx, 0.0, 0.0);
            self.endPanRect = CGRectOffset(self.centerContainerView.bounds, tx, 0);
        }
        else{
            transform = CATransform3DMakeScale(percentVisible, 1.f, 1.f);
            transform = CATransform3DTranslate(transform, self.maximumLeftDrawerWidth*(percentVisible-1.f)/2, 0.f, 0.f);
        }
    }
    else if(drawerSide == SHDrawerSideStateRight){
        sideDrawerViewController = self.rightDrawerViewController;
        CGFloat distance = MAX(self.maximumRightDrawerWidth, self.visibleRightDrawerWidth);
        if(percentVisible <= 1.f){
            CGFloat tx = (distance)/1-(distance*percentVisible)/1;
            transform = CATransform3DMakeTranslation(tx, 0.0, 0.0);
            self.endPanRect = CGRectOffset(self.centerContainerView.bounds, tx, 0);
        }
        else{
            transform = CATransform3DMakeScale(percentVisible, 1.f, 1.f);
            transform = CATransform3DTranslate(transform, -self.maximumRightDrawerWidth*(percentVisible-1.f)/2, 0.f, 0.f);
        }
    }
    
    [sideDrawerViewController.view.layer setTransform:transform];
};

- (void)resetDrawerVisualStateForDrawerSide:(SHDrawerSideState)drawerSide{
    UIViewController *sideDrawerViewController = [self sideDrawerViewControllerForSide:drawerSide];
    
    [sideDrawerViewController.view.layer setAnchorPoint:CGPointMake(0.5f, 0.5f)];
    [sideDrawerViewController.view.layer setTransform:CATransform3DIdentity];
    [sideDrawerViewController.view setAlpha:1.0];
}

- (CGFloat)roundedOriginXForDrawerConstriants:(CGFloat)originX {
    
    if (originX < -self.maximumRightDrawerWidth) {
        if (self.shouldStretchDrawer &&
            self.rightDrawerViewController) {
            CGFloat maxOvershoot = (CGRectGetWidth(self.centerContainerView.frame)-self.maximumRightDrawerWidth)*MMDrawerOvershootPercentage;
            return originXForDrawerOriginAndTargetOriginOffset(originX, -self.maximumRightDrawerWidth, maxOvershoot);
        }
        else{
            return -self.maximumRightDrawerWidth;
        }
    }
    else if(originX > self.maximumLeftDrawerWidth){
        if (self.shouldStretchDrawer &&
            self.leftDrawerViewController) {
            CGFloat maxOvershoot = (CGRectGetWidth(self.centerContainerView.frame)-self.maximumLeftDrawerWidth)*MMDrawerOvershootPercentage;
            return originXForDrawerOriginAndTargetOriginOffset(originX, self.maximumLeftDrawerWidth, maxOvershoot);
        }
        else{
            return self.maximumLeftDrawerWidth;
        }
    }
    
    return originX;
}

static inline CGFloat originXForDrawerOriginAndTargetOriginOffset(CGFloat originX, CGFloat targetOffset, CGFloat maxOvershoot){
    CGFloat delta = ABS(originX - targetOffset);
    CGFloat maxLinearPercentage = MMDrawerOvershootLinearRangePercentage;
    CGFloat nonLinearRange = maxOvershoot * maxLinearPercentage;
    CGFloat nonLinearScalingDelta = (delta - nonLinearRange);
    CGFloat overshoot = nonLinearRange + nonLinearScalingDelta * nonLinearRange/sqrt(pow(nonLinearScalingDelta,2.f) + 15000);
    
    if (delta < nonLinearRange) {
        return originX;
    }
    else if (targetOffset < 0) {
        return targetOffset - round(overshoot);
    }
    else{
        return targetOffset + round(overshoot);
    }
}

- (void)finishAnimationForPanGestureWithXVelocity:(CGFloat)xVelocity completion:(void(^)(BOOL finished))completion {
    
//    CGFloat currentOriginX = CGRectGetMinX(self.centerContainerView.frame);
    CGFloat currentOriginX = CGRectGetMinX(self.endPanRect);
    
    CGFloat animationVelocity = MAX(ABS(xVelocity),self.panVelocityXAnimationThreshold*2);
    
    if(self.drawerSideState == SHDrawerSideStateLeft) {
        CGFloat midPoint = self.maximumLeftDrawerWidth / 2.0;
        if(xVelocity > self.panVelocityXAnimationThreshold){
            [self openDrawerSide:SHDrawerSideStateLeft animated:YES velocity:animationVelocity animationOptions:UIViewAnimationOptionCurveEaseOut completion:completion];
        }
        else if(xVelocity < -self.panVelocityXAnimationThreshold){
            [self closeDrawerAnimated:YES velocity:animationVelocity animationOptions:UIViewAnimationOptionCurveEaseOut completion:completion];
        }
        else if (currentOriginX < midPoint) {
            [self closeDrawerAnimated:YES completion:completion];
        }
        else {
            [self openDrawerSide:SHDrawerSideStateLeft animated:YES completion:completion];
        }
    }
    else if(self.drawerSideState == SHDrawerSideStateRight){
        currentOriginX = CGRectGetMaxX(self.centerContainerView.frame);
        CGFloat midPoint = (CGRectGetWidth(self.childContainerView.bounds)-self.maximumRightDrawerWidth) + (self.maximumRightDrawerWidth / 2.0);
        if(xVelocity > self.panVelocityXAnimationThreshold){
            [self closeDrawerAnimated:YES velocity:animationVelocity animationOptions:UIViewAnimationOptionCurveEaseOut completion:completion];
        }
        else if (xVelocity < -self.panVelocityXAnimationThreshold){
            [self openDrawerSide:SHDrawerSideStateRight animated:YES velocity:animationVelocity animationOptions:UIViewAnimationOptionCurveEaseOut completion:completion];
        }
        else if(currentOriginX > midPoint){
            [self closeDrawerAnimated:YES completion:completion];
        }
        else {
            [self openDrawerSide:SHDrawerSideStateRight animated:YES completion:completion];
        }
    }
    else {
        if(completion){
            completion(NO);
        }
    }
}

#pragma mark - Delegate
#pragma mark  UIGestureRecognizerDelegate
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    
    if(self.drawerSideState == SHDrawerSideStateNormal){
        MMOpenDrawerGestureMode possibleOpenGestureModes = [self possibleOpenGestureModesForGestureRecognizer:gestureRecognizer
                                                                                                    withTouch:touch];
        return ((self.openDrawerGestureModeMask & possibleOpenGestureModes)>0);
    }
    else{
        MMCloseDrawerGestureMode possibleCloseGestureModes = [self possibleCloseGestureModesForGestureRecognizer:gestureRecognizer
                                                                                                       withTouch:touch];
        BOOL res = ((self.closeDrawerGestureModeMask & possibleCloseGestureModes)>0);
        return res;
    }
}

#pragma mark - Open or close drawer

- (void)toggleDrawerSide:(SHDrawerSideState)drawerSide animated:(BOOL)animated completion:(void(^)(BOOL finished))completion {
    NSParameterAssert(drawerSide!= SHDrawerSideStateNormal);
    if (self.drawerSideState == SHDrawerSideStateNormal) {
        [self openDrawerSide:drawerSide animated:animated completion:completion];
    } else {
        if((drawerSide == SHDrawerSideStateLeft &&
           self.drawerSideState == SHDrawerSideStateLeft) ||
           (drawerSide == SHDrawerSideStateRight &&
           self.drawerSideState == SHDrawerSideStateRight))
        {
            [self closeDrawerAnimated:animated completion:completion];
        } else if(completion) {
            completion(NO);
        }
    }
}

- (void)closeDrawerAnimated:(BOOL)animated completion:(void(^)(BOOL finished))completion {
    [self closeDrawerAnimated:animated velocity:self.animationVelocity animationOptions:UIViewAnimationOptionCurveEaseInOut completion:completion];
}

-(void)closeDrawerAnimated:(BOOL)animated velocity:(CGFloat)velocity animationOptions:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion{
    if(self.isAnimatingDrawer){
        if(completion){
            completion(NO);
        }
    }
    else {
        [self setAnimatingDrawer:animated];
        CGRect newFrame = self.childContainerView.bounds;
        
        CGFloat distance = ABS(CGRectGetMinX(self.centerContainerView.frame));
        NSTimeInterval duration = MAX(distance/ABS(velocity), SHDrawerMinimumAnimationDuration);
        
//        BOOL leftDrawerVisible = CGRectGetMinX(self.centerContainerView.frame) > 0;
//        BOOL rightDrawerVisible = CGRectGetMinX(self.centerContainerView.frame) < 0;
        
        BOOL leftDrawerVisible = self.leftDrawerViewController.view.hidden == NO;
        BOOL rightDrawerVisible = self.rightDrawerViewController.view.hidden == NO;
        
        SHDrawerSideState visibleSide = SHDrawerSideStateNormal;
        CGFloat percentVisble = 0.0;
        
        if(leftDrawerVisible){
            CGFloat visibleDrawerPoints = CGRectGetMinX(self.centerContainerView.frame);
            percentVisble = MAX(0.0,visibleDrawerPoints/self.maximumLeftDrawerWidth);
            visibleSide = SHDrawerSideStateLeft;
        }
        else if(rightDrawerVisible){
            CGFloat visibleDrawerPoints = CGRectGetWidth(self.centerContainerView.frame)-CGRectGetMaxX(self.centerContainerView.frame);
            percentVisble = MAX(0.0,visibleDrawerPoints/self.maximumRightDrawerWidth);
            visibleSide = SHDrawerSideStateRight;
        }
        
        UIViewController * sideDrawerViewController = [self sideDrawerViewControllerForSide:visibleSide];
        
//        [self updateDrawerVisualStateForDrawerSide:visibleSide percentVisible:percentVisble];
        
        [sideDrawerViewController beginAppearanceTransition:NO animated:animated];
        
        [UIView
         animateWithDuration:(animated?duration:0.0)
         delay:0.0
         options:options
         animations:^{
            self.maskControl.alpha = 0;
            [self.centerContainerView setFrame:newFrame];
            [self updateDrawerVisualStateForDrawerSide:visibleSide percentVisible:0.0];
         }
         completion:^(BOOL finished) {
            [sideDrawerViewController endAppearanceTransition];
            [self setDrawerSideState:SHDrawerSideStateNormal];
            [self.maskControl removeFromSuperview];
            [self resetDrawerVisualStateForDrawerSide:visibleSide];
            [self setAnimatingDrawer:NO];
            if(completion){
                completion(finished);
            }
         }];
    }
}

- (void)openDrawerSide:(SHDrawerSideState)drawerSide animated:(BOOL)animated completion:(void(^)(BOOL finished))completion {
    NSParameterAssert(drawerSide != SHDrawerSideStateNormal);
    
    [self openDrawerSide:drawerSide animated:animated velocity:self.animationVelocity animationOptions:UIViewAnimationOptionCurveEaseInOut completion:completion];
}

-(void)openDrawerSide:(SHDrawerSideState)drawerSide animated:(BOOL)animated velocity:(CGFloat)velocity animationOptions:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion
{
    NSParameterAssert(drawerSide != SHDrawerSideStateNormal);
    if (self.isAnimatingDrawer) {
        if(completion){
            completion(NO);
        }
    }
    else {
        [self setAnimatingDrawer:animated];
        UIViewController * sideDrawerViewController = [self sideDrawerViewControllerForSide:drawerSide];
        if (self.drawerSideState != drawerSide) {
          [self prepareToPresentDrawer:drawerSide animated:animated];
        }
        
        if(sideDrawerViewController){
            CGRect newFrame;
            CGRect oldFrame = self.centerContainerView.frame;
            if(drawerSide == SHDrawerSideStateLeft){
                newFrame = self.centerContainerView.frame;
                newFrame.origin.x = self.maximumLeftDrawerWidth;
            }
            else {
                newFrame = self.centerContainerView.frame;
                newFrame.origin.x = 0-self.maximumRightDrawerWidth;
            }
            
            CGFloat distance = ABS(CGRectGetMinX(oldFrame)-newFrame.origin.x);
            NSTimeInterval duration = MAX(distance/ABS(velocity), SHDrawerMinimumAnimationDuration);
            
//            [self.centerContainerView addSubview:self.maskControl];
            [self.childContainerView insertSubview:self.maskControl atIndex:0];
            [self.childContainerView sendSubviewToBack:self.maskControl];
            self.maskControl.alpha = 0;
            
            [UIView
             animateWithDuration:(animated?duration:0.0)
             delay:0.0
             options:options
             animations:^{
                self.maskControl.alpha = 1;
//                [self.centerContainerView setFrame:newFrame];
                [self updateDrawerVisualStateForDrawerSide:drawerSide percentVisible:1.0];
             }
             completion:^(BOOL finished) {
                //End the appearance transition if it already wasn't open.
                if(drawerSide != self.drawerSideState){
                    [sideDrawerViewController endAppearanceTransition];
                }
                [self setDrawerSideState:drawerSide];
                [self resetDrawerVisualStateForDrawerSide:drawerSide];
                [self setAnimatingDrawer:NO];
                if(completion){
                    completion(finished);
                }
             }];
        }
    }
}

#pragma mark - Setter
- (void)setAnimatingDrawer:(BOOL)animatingDrawer {
    _animatingDrawer = animatingDrawer;
    self.view.userInteractionEnabled = !_animatingDrawer;
}

- (void)setDrawerSideState:(SHDrawerSideState)drawerSideState {
    if (_drawerSideState != drawerSideState) {
        _drawerSideState = drawerSideState;
        if (_drawerSideState == SHDrawerSideStateNormal) {
            self.leftDrawerViewController.view.hidden = YES;
            self.rightDrawerViewController.view.hidden = YES;
        }
    }
}

- (void)setCenterViewController:(UIViewController *)centerViewController {
    [self setCenterViewController:centerViewController animated:NO];
}

- (void)setCenterViewController:(UIViewController *)centerViewController animated:(BOOL)animated {
    if (_centerViewController == centerViewController) { return; }
    
    // 初始化 _centerContainerView
    if (!_centerContainerView) {
        CGRect centerFrame = self.childContainerView.bounds;
        _centerContainerView = [[SHCenterContainerView alloc] initWithFrame:centerFrame];
        _centerContainerView.backgroundColor = UIColor.clearColor;
        _centerContainerView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
        [self.childContainerView addSubview:_centerContainerView];
    }
    
    // 移除旧centerViewController
    UIViewController * oldCenterViewController = self.centerViewController;
    if(oldCenterViewController){
        [oldCenterViewController willMoveToParentViewController:nil];
        if(animated == NO){
            [oldCenterViewController beginAppearanceTransition:NO animated:NO];
        }
        [oldCenterViewController.view removeFromSuperview];
        if(animated == NO){
            [oldCenterViewController endAppearanceTransition];
        }
        [oldCenterViewController removeFromParentViewController];
    }
    
    // 添加新centerViewController
    _centerViewController = centerViewController;
    
    [self addChildViewController:self.centerViewController];
    [self.centerViewController.view setFrame:self.childContainerView.bounds];
    [self.centerContainerView addSubview:self.centerViewController.view];
    [self.childContainerView bringSubviewToFront:self.centerContainerView];
    [self.centerViewController.view setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
    
    if(animated == NO){
        // If drawer is offscreen, then viewWillAppear: will take care of this
        if(self.view.window) {
            [self.centerViewController beginAppearanceTransition:YES animated:NO];
            [self.centerViewController endAppearanceTransition];
        }
        [self.centerViewController didMoveToParentViewController:self];
    }
}

- (void)setDrawerViewController:(UIViewController *)drawerViewController drawerSideState:(SHDrawerSideState)drawerSideState {
    NSParameterAssert(drawerSideState != SHDrawerSideStateNormal);
    
    UIViewController *currentSideViewController = [self sideDrawerViewControllerForSide:drawerSideState];

    if (currentSideViewController == drawerViewController) { return; }

    if (currentSideViewController != nil) {
        [currentSideViewController beginAppearanceTransition:NO animated:NO];
        [currentSideViewController.view removeFromSuperview];
        [currentSideViewController endAppearanceTransition];
        [currentSideViewController willMoveToParentViewController:nil];
        [currentSideViewController removeFromParentViewController];
    }
    
    UIViewAutoresizing autoResizingMask = 0;
    if (drawerSideState == SHDrawerSideStateLeft) {
        _leftDrawerViewController = drawerViewController;
        autoResizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight;
        
    }
    else if(drawerSideState == SHDrawerSideStateRight){
        _rightDrawerViewController = drawerViewController;
        autoResizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
    }
    
    if(drawerViewController){
        [self addChildViewController:drawerViewController];
        
        if((self.drawerSideState == drawerSideState) &&
           [self.childContainerView.subviews containsObject:self.centerContainerView]){
//            [self.childContainerView insertSubview:drawerViewController.view aboveSubview:self.centerContainerView];
            
            [self.childContainerView addSubview:drawerViewController.view];
            [drawerViewController beginAppearanceTransition:YES animated:NO];
            [drawerViewController endAppearanceTransition];
        }
        else{
            [self.childContainerView addSubview:drawerViewController.view];
            drawerViewController.view.layer.zPosition = 100; // 遮挡导航栏
//            [self.childContainerView sendSubviewToBack:drawerViewController.view];
//            [self.childContainerView insertSubview:drawerViewController.view aboveSubview:self.centerContainerView];
            [drawerViewController.view setHidden:YES];
        }
        [drawerViewController didMoveToParentViewController:self];
        [drawerViewController.view setAutoresizingMask:autoResizingMask];
        
        CGRect visibleDrawerFrame = [self visibleRectForDrawerSideState:drawerSideState];
        
        [drawerViewController.view setFrame:visibleDrawerFrame];
    }
}

- (void)setLeftDrawerViewController:(UIViewController *)leftDrawerViewController {
    [self setDrawerViewController:leftDrawerViewController drawerSideState:SHDrawerSideStateLeft];
}

- (void)setRightDrawerViewController:(UIViewController *)rightDrawerViewController {
    [self setDrawerViewController:rightDrawerViewController drawerSideState:SHDrawerSideStateRight];
}

#pragma mark - Getter

- (UIControl *)maskControl {
    if (!_maskControl) {
        _maskControl = [[UIControl alloc] initWithFrame:self.centerContainerView.bounds];
        _maskControl.backgroundColor = [UIColor.blackColor colorWithAlphaComponent:0.5];
        _maskControl.userInteractionEnabled = NO;
        [_maskControl addTarget:self action:@selector(maskControlClick:) forControlEvents:UIControlEventTouchUpInside];
    }
    return _maskControl;
}

- (SHChildContainerView *)childContainerView {
    if (!_childContainerView) {
        CGRect frame = self.view.bounds;
        if (!_childContainerView) {
            _childContainerView = [[SHChildContainerView alloc] initWithFrame:frame];
            _childContainerView.backgroundColor = UIColor.clearColor;
            _childContainerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
            [self.view addSubview:_childContainerView];
        }
    }
    return _childContainerView;
}

// TODO: Dush 处理有误，需要修改， 但是影响也不大
- (CGFloat)visibleLeftDrawerWidth{
    return MAX(0.0,CGRectGetMinX(self.centerContainerView.frame));
}

- (CGFloat)visibleRightDrawerWidth{
    if(CGRectGetMinX(self.centerContainerView.frame)<0){
        return CGRectGetWidth(self.childContainerView.bounds)-CGRectGetMaxX(self.centerContainerView.frame);
    }
    else {
        return 0.0f;
    }
}


@end
